<?php
/**
 * The PantsComment class represents a comment attached to a blog article.
 *
 * @author Ryan Grove <ryan@wonko.com>
 * @copyright Copyright (c) 2007 Ryan Grove. All rights reserved.
 * @license http://opensource.org/licenses/bsd-license.php New BSD License
 */
class PantsComment extends PantsObject {
  public $id;
  public $article_id;
  public $parent_id;
  public $author;
  public $email;
  public $url;
  public $title;
  public $content;
  public $posted;
  public $ip;

  public $article_title;

  // -- Public Static Methods --------------------------------------------------
  
  /**
   * Creates a new PantsComment object based on the form input in the $_POST
   * response. Performs all necessary input validation and filtering.
   *
   * @return PantsComment new comment
   */
  public static function createFromResponse() {
    $article_id = Pants::getResponse('article_id');

    if (!$article_id || !PantsArticle::getById($article_id)) {
      throw new PantsException('Invalid article id.');
    }
    
    // Is this an evil robot?
    if (Pants::getResponse('captcha') || Pants::getResponse('comment')) {
      Pants::error('I smell spam', 'You smell like an evil robot to me.');
    }

    // Validate author name.
    $author = trim(Pants::getResponse('author'));

    if (!$author || strlen($author) > 32) {
      throw new PantsException('Please enter your name.');
    }

    // Validate email.
    $email = trim(Pants::getResponse('email'));

    if (strlen($email) > 64) {
      throw new PantsException('Please enter a shorter email address or leave the email field blank.');
    }

    // Validate URL.
    $url = trim(Pants::getResponse('url'));

    if (strlen($url) && !preg_match('/^https?:\/\//i', $url)) {
      $url = preg_replace('/^.*:(\/\/)?/i', '', $url);
      $url = "http://$url";
    }

    if (strlen($url) > 128) {
      throw new PantsException('Please enter a shorter URL or leave the URL field blank.');
    }

    // Validate title.
    $title = trim(Pants::getResponse('title', 'No title'));

    if (strlen($title) > 255) {
      throw new PantsException('Please enter a shorter comment title.');
    }

    if (strlen($title) == 0) {
      $title = 'No title';
    }

    // Validate content.
    $content = Pants::filterHTML(trim(Pants::getResponse('content', '')));
    
    if (!strlen($content)) {
      throw new PantsException('Cat got your tongue?');
    }

    // Autoformat content.
    // if (stripos($content, '<p>') === false) {
    //   $content = preg_replace('/\s*([\w\W]+?)(?:[\r\n]{2,}|$)/', "<p>\n\\1\n</p>\n\n",
    //       $content);
    // }
    // if (stripos($content, '<p>') === false
    //     && stripos($content, '<br/>') === false
    //     && stripos($content, '<br />') === false) {
    //   $content = nl2br($content);
    // }

    // Set cookies.
    setcookie('author', $author, time() + 31536000, SITE_RELATIVE_URL);
    setcookie('email', $email, time() + 31536000, SITE_RELATIVE_URL);
    setcookie('url', $url, time() + 31536000, SITE_RELATIVE_URL);

    return new PantsComment(0, $article_id, 0, $author, $email, $url, $title,
        $content);
  }

  /**
   * Gets an array of comments attached to the specified article id.
   *
   * @param int $article_id
   * @return array array of PantsComment objects
   */
  public static function getByArticleId($article_id) {
    return Pants::query('comments.getByArticleId',
        array('article_id' => $article_id));
  }

  /**
   * Gets the total number of comments in the database.
   *
   * @return int total number of comments in the database
   */
  public static function getCount() {
    $result = Pants::query('comments.getCount');

    if ($result) {
      $result = $result->fetch_array();
      return $result[0];
    }

    return 0;
  }

  /**
   * Gets an array of recently posted comments from the database.
   *
   * @param int $limit maximum number of comments to return
   * @param int $offset offset at which to begin returning comments
   * @return array array of PantsComment objects
   */
  public static function getRecent($limit = 10, $offset = 0) {
    return Pants::query('comments.getRecent', array(
      'limit'  => $limit,
      'offset' => $offset
    ));
  }

  /**
   * Creates and returns a PantsComment object built from the specified database
   * row.
   *
   * @param array $row database row
   * @return PantsComment
   */
  public static function load($row) {
    return new PantsComment($row['id'], $row['article_id'], $row['parent_id'],
        $row['author'], $row['email'], $row['url'], $row['title'],
        $row['content'], $row['posted'], $row['ip'], $row['article_title']);
  }

  /**
   * Performs a full text search and returns comments matching the specified
   * query.
   *
   * @param string $query search query
   * @return array array of PantsComment objects
   */
  public static function search($query) {
    return Pants::query('comments.search', array('query' => $query));
  }

  // -- Private Instance Methods -----------------------------------------------

  private function paragraph($matches) {
    // Check for block-level elements.
    if (preg_match('/<(?:address|blockquote|dl|h[1-6]|ol|pre|table|ul)>/i',
        $matches[1])) {
      return $matches[1];
    } else {
      return '<p>'.$matches[1].'</p>';
    }
  }
  
  // -- Public Instance Methods ------------------------------------------------
  
  /**
   * Initializes a new PantsComment object.
   *
   * @param int $id comment id
   * @param int $article_id article id to which this comment is attached
   * @param int $parent_id deprecated
   * @param string $author author's name
   * @param string $email author's email address
   * @param string $url author's URL
   * @param string $title comment title
   * @param string $content comment content
   * @param int $posted timestamp when comment was posted
   * @param string $ip author's IP address
   * @param string $article_title title of the article to which the comment is
   *   attached
   */
  public function __construct($id = 0, $article_id = 0, $parent_id = 0,
      $author = '', $email = '', $url = '', $title = '', $content = '',
      $posted = 0, $ip = '', $article_title = '') {

    $this->id            = $id;
    $this->article_id    = $article_id;
    $this->parent_id     = $parent_id;
    $this->author        = $author;
    $this->email         = $email;
    $this->url           = $url;
    $this->title         = $title;
    $this->content       = $content;
    $this->posted        = $posted == 0 ? time() : $posted;
    $this->ip            = $ip == '' ? $_SERVER['REMOTE_ADDR'] : $ip;
    $this->article_title = $article_title;
  }

  public function getContent() {
    if (stripos($this->content, '<p>') === false &&
        !preg_match('/(?:<br\s*\/>\s*){2,}/', $this->content)) {
      return preg_replace_callback('/\s*([\w\W]+?)(?:\n{2,}|(?:\r\n){2,}|$)/', 
        array($this, 'paragraph'), $this->content);;
    }

    return $this->content;
  }
  
  /**
   * Persists this comment to the database.
   *
   * @return mysqli_result database query result
   */
  public function save() {
    if ($this->id == 0) {
      $result = Pants::query('comments.create', array(
        'article_id' => $this->article_id,
        'parent_id'  => $this->parent_id,
        'author'     => $this->author,
        'email'      => $this->email,
        'url'        => $this->url,
        'title'      => $this->title,
        'content'    => $this->content,
        'ip'         => $this->ip
      ));

      if ($result) {
        $this->id = Pants::$db->getInsertId();
      }
    }

    return $result;
  }
}
?>